package com.example.sonone.util;


import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.Date;
import java.util.Objects;

/**
 * 日期工具类
 *
 * @author zhangpeng
 * @date 2019-05-27
 */
@Slf4j
public class DateUtil {

    public static final String YYYYDOTMM = "yyyy.MM";

    public final static String YYYY = "yyyy";

    public final static String MM = "MM";

    public final static String MM_POINT_DD = "MM.DD";

    public final static String DD = "dd";

    public final static String YYYY_MM_DD = "yyyy-MM-dd";

    public final static String YYYYMMDD = "yyyyMMdd";

    public final static String YYYY_MM_S = "yyyy/MM";

    public final static String YYYY_MM = "yyyy-MM";

    public final static String YYYYMM = "yyyyMM";

    public final static String YYYY_WW = "yyyy-WW";

    public final static String YYYYWW = "yyyyWW";

    public final static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";

    public final static String YYYYMMDDHHMMSSSSS = "yyyyMMddHHmmssSSS";

    public final static String HH_MM_SS = "HH:mm:ss";

    public final static String HH_MM = "HH:mm";

    public final static String DATE_RULE_COMMON = "yyyy-MM-dd HH:mm:ss";

    public final static String YYYY_MM_DD_HH_MM = "yyyy-MM-dd HH:mm";

    public final static String YYYY_MM_DD_HH_MM_SS_SSS = "yyyy-MM-dd HH:mm:ss.SSS";

    public final static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd-HH-mm-ss";

    public final static String YYYY_MM_DD_HH_MM_SS_SSS_CN = "yyyy年MM月dd日HH时mm分ss秒";

    public final static String YYMMDD = "yyMMdd";

    public static final String DEFAULT_TIME_STR = "1970-01-01 08:00:01";

    public static final String OTHER_DEFAULT_TIME_STR = "1970-01-01 00:00:00";

    public static final String LOCAL_TIMEZONE = "Asia/Shanghai";

    public static final String YEAR_STRING = "1970";

    public static final String DAY_END = " 23:59:59";

    public static final long DAYS_MILLIONS_SECONDS = 86400000;

    public static final long HOURS_MILLIONS_SECONDS = 60 * 60 * 1000;

    public static final long HALF_HOURS_MILLIONS_SECONDS = 30 * 60 * 1000;

    public static final long MINUS_MILLIONS_SECONDS = 60 * 1000;

    public static final int MINUTES_OF_HALF_HOUR = 30;

    public static final Integer DEFAULT_YEAR = 1970;

    public static final String DEFAULT_DATE_STR = "1970-01-01";

    public static final String FIRST_DAY = "-01";

    public static final LocalDateTime LOCAL_DATE_TIME = LocalDateTime.of(1970, 1, 1, 8, 0, 1, 0);

    public static final LocalDate LOCAL_DATE = LocalDate.of(1970, 1, 1);

    public static final LocalTime BEGIN_TIME = LocalTime.of(0, 0, 0, 0);

    public static final LocalTime END_TIME = LocalTime.of(23, 59, 59, 999);

    /**
     * LocalDateTime to Date
     *
     * @param localDateTime LocalDateTime
     * @return Date
     */
    public static Date toDate(LocalDateTime localDateTime) {
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zdt = localDateTime.atZone(zoneId);
        return Date.from(zdt.toInstant());
    }

    /**
     * Date to LocalDateTime
     *
     * @param date Date
     * @return LocalDateTime
     */
    public static LocalDateTime toLocalDateTime(Date date) {
        ZoneId zoneId = ZoneId.systemDefault();
        return date.toInstant().atZone(zoneId).toLocalDateTime();
    }

    /**
     * 判断日期是否为默认初始时间
     *
     * @param date 时间
     * @return true表示是默认初始时间, false反之
     */
    public static boolean isInitTime(LocalDateTime date) {
        return date != null && date.isEqual(Objects.requireNonNull(DateUtil.parseTimeString(DateUtil.DEFAULT_TIME_STR)));
    }

    /**
     * 如果时间是数据库默认的1970年开头的时间，则返回空,否则不变
     *
     * @param localDateTime 时间
     * @return 时间
     */
    public static LocalDateTime convertDefaultTimeToNull(LocalDateTime localDateTime) {
        return Objects.isNull(localDateTime) ? null :
                (DEFAULT_YEAR.equals(localDateTime.getYear()) ? null : localDateTime);
    }

    /**
     * 日期格式化－将<code>Date</code>类型的日期格式化为<code>String</code>型
     *
     * @param date    待格式化的日期
     * @param pattern 时间样式
     * @return 一个被格式化了的<code>String</code>日期
     */
    public static String formatWithoutDefaultYear(LocalDateTime date, String pattern) {
        if (date == null) {
            return "";
        } else {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
            return formatter.format(date);
        }
    }

    /**
     * 日期格式化－将<code>Date</code>类型的日期格式化为<code>String</code>型
     *
     * @param date    待格式化的日期
     * @param pattern 时间样式
     * @return 一个被格式化了的<code>String</code>日期
     */
    public static String format(LocalDateTime date, String pattern) {
        if (date == null || DEFAULT_YEAR.equals(date.getYear())) {
            return "";
        } else {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
            return formatter.format(date);
        }
    }

    /**
     * 日期格式化－将<code>Date</code>类型的日期格式化为<code>String</code>型
     *
     * @param date 待格式化的日期
     * @return 一个被格式化了的<code>String</code>日期
     */
    public static String format(LocalDateTime date) {
        return format(date, DATE_RULE_COMMON);
    }

    /**
     * LocalDate转Date
     *
     * @param localDate LocalDate
     * @return Date
     */
    public static Date localDate2Date(LocalDate localDate) {
        if (null == localDate) {
            return null;
        }
        ZonedDateTime zonedDateTime = localDate.atStartOfDay(ZoneId.systemDefault());
        return Date.from(zonedDateTime.toInstant());
    }

    /**
     * 获取指定日期的毫秒
     *
     * @param time LocalDateTime
     */
    public static Long getMilliByTime(LocalDateTime time) {
        return time.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

    /**
     * 获取一天的开始时间，
     *
     * @param time time
     * @return LocalDateTime
     */
    public static LocalDateTime beginOfDay(LocalDateTime time) {
        if (null == time) {
            return null;
        }
        return time.withHour(0)
                .withMinute(0)
                .withSecond(0)
                .withNano(0);
    }

    /**
     * 获取一天的结束时间
     *
     * @param time LocalDateTime
     * @return LocalDateTime
     */
    public static LocalDateTime endOfDay(LocalDateTime time) {
        if (null == time) {
            return null;
        }
        return time.withHour(23)
                .withMinute(59)
                .withSecond(59)
                .withNano(999);
    }

    /**
     * 获取前端正确显示的时间
     *
     * @param originalDate 传入时间
     * @return 前端正确显示的时间；把"1970-01-01 08:00:01"变为""
     */
    public static String getRealDate(String originalDate) {
        return DEFAULT_TIME_STR.equals(originalDate) ? "" : originalDate;
    }

    /**
     * 日期格式化，若是默认时间包含1970，则返回默认的值
     *
     * @param localDateTime 待格式化日期
     * @return 格式化后的日期
     */
    public static String cover1970ToEmpty(LocalDateTime localDateTime) {
        return localDateTime == null || DEFAULT_YEAR.equals(localDateTime.getYear()) ? "" :
                localDateTime.format(DateTimeFormatter.ofPattern(DATE_RULE_COMMON));
    }

    /**
     * 格式转换时间字符串
     *
     * @param timestampStr String
     * @return String
     */
    public static String cover1970ToEmpty(String timestampStr) {
        return (StringUtils.isBlank(timestampStr) || timestampStr.contains(DEFAULT_DATE_STR)) ? "" : timestampStr;
    }

    public static LocalDateTime cover1970ToNull(LocalDateTime localDateTime) {
        return localDateTime == null || DEFAULT_YEAR.equals(localDateTime.getYear()) ? null : localDateTime;
    }

    public static String cover1970ToEmpty(LocalDate localDate) {
        return localDate == null || DEFAULT_YEAR.equals(localDate.getYear()) ? "" :
                localDate.format(DateTimeFormatter.ofPattern(YYYY_MM_DD));
    }

    public static LocalDateTime conver1970ToNull(LocalDateTime localDateTime) {
        return localDateTime == null || DEFAULT_YEAR.equals(localDateTime.getYear()) ? null :
                localDateTime;
    }

    public static LocalDate conver1970ToNull(LocalDate localDate) {
        return localDate == null || DEFAULT_YEAR.equals(localDate.getYear()) ? null :
                localDate;
    }

    /**
     * 计算两个日期相差的天数，end-start
     *
     * @param start LocalDateTime
     * @param end   LocalDateTime
     * @return long
     */
    public static int daysBetween(LocalDateTime start, LocalDateTime end) {
        int daysNum = (int) (start.toLocalDate().toEpochDay() - end.toLocalDate().toEpochDay());
        return Math.abs(daysNum);
    }

    /**
     * 时间差 非绝对值
     *
     * @param end   减数
     * @param start 被减数
     * @return 结果
     */
    public static long hoursReduction(LocalDateTime start, LocalDateTime end) {
        return (DateUtil.getMilliByTime(start) - DateUtil.getMilliByTime(end)) / (60 * 60 * 1000);
    }

    /**
     * 计算两个日期相差的小时，end-start 绝对值
     *
     * @param start Date
     * @param end   Date
     * @return long
     */
    public static long hoursBetween(LocalDateTime start, LocalDateTime end) {
        Duration duration = Duration.between(start, end);
        return Math.abs(duration.toHours());
    }

    /**
     * 获取当前时间的月开始时间
     *
     * @param time LocalDateTime
     * @return LocalDateTime
     */
    public static LocalDateTime getMonthStartTime(LocalDateTime time) {
        if (null == time) {
            return null;
        }

        return time.with(TemporalAdjusters.firstDayOfMonth())
                .withHour(0)
                .withMinute(0)
                .withSecond(0)
                .withNano(0);
    }

    /**
     * 获取当前时间的下个月开始时间
     *
     * @param time LocalDateTime
     * @return LocalDateTime
     */
    public static LocalDateTime getNextMonthStartTime(LocalDateTime time) {
        if (null == time) {
            return null;
        }
        return time.plusMonths(1)
                .with(TemporalAdjusters.firstDayOfMonth())
                .withHour(0)
                .withMinute(0)
                .withSecond(0)
                .withNano(0);
    }

    /**
     * 获取当前季度的开始时间
     *
     * @param time LocalDateTime
     * @return LocalDateTime
     */
    public static LocalDateTime getQuarterStartTime(LocalDateTime time) {
        if (null == time) {
            return null;
        }
        LocalDate now = LocalDateTime.now().toLocalDate();
        Month month = Month.of(now.getMonth().firstMonthOfQuarter().getValue());
        return LocalDateTime.of(LocalDate.of(now.getYear(), month, 1), LocalTime.MIN);
    }

    /**
     * 获取下个季度的开始时间
     *
     * @param time LocalDateTime
     * @return LocalDateTime
     */
    public static LocalDateTime getNextQuarterStartTime(LocalDateTime time) {
        if (null == time) {
            return null;
        }
        LocalDate now = LocalDateTime.now().toLocalDate();
        Month month = Month.of(now.getMonth().firstMonthOfQuarter().getValue());
        LocalDateTime curQuarter = LocalDateTime.of(LocalDate.of(now.getYear(), month, 1), LocalTime.MIN);
        return curQuarter.plusMonths(3);
    }

    /**
     * 将字符串解析为LocalDateTime 只处理yyyy-MM-dd HH:mm:ss 的格式
     *
     * @param timeStr 时间
     * @return 时间
     */
    public static LocalDateTime parseTimeString(String timeStr) {
        if (StringUtils.isEmpty(timeStr)) {
            return null;
        }
        return LocalDateTime.parse(timeStr, DateTimeFormatter.ofPattern(DATE_RULE_COMMON));
    }

    /**
     * 将字符串解析为LocalDateTime 只处理yyyy-MM-dd的格式，并设置为当天开始时间
     *
     * @param timeStr 时间
     * @return 时间
     */
    public static LocalDateTime parseDateString(String timeStr) {
        if (StringUtils.isEmpty(timeStr)) {
            return null;
        }
        LocalDate localDate = LocalDate.parse(timeStr, DateTimeFormatter.ofPattern(YYYY_MM_DD));
        return localDate.atStartOfDay();
    }

    /**
     * 获取时间加上或减去分钟后的时间
     *
     * @param time    时间
     * @param minutes 加减的分钟数
     * @return time
     */
    public static LocalDateTime getMinuteDate(LocalDateTime time, long minutes) {
        if (null == time) {
            return null;
        }
        return time.plusMinutes(minutes);
    }

    /**
     * 将时间戳（到秒级）转换成LocalDateTime
     *
     * @param timestamp 精确到秒的时间戳
     * @return LocalDateTime
     */
    public static LocalDateTime parseTimestamp(Long timestamp) {
        return LocalDateTime.ofEpochSecond(timestamp, 0, ZoneOffset.ofHours(8));
    }

    /**
     * 毫秒 转 LocalDateTime
     *
     * @param millisecond 日期对应的毫秒
     * @return java.time.LocalDateTime LocalDateTime
     * @author Gaosl
     */
    public static LocalDateTime ms2LocalDateTime(Long millisecond) {
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(millisecond), ZoneId.systemDefault());
    }

    /**
     * 获取当前月份的第一天
     *
     * @return 当前月份的第一天
     */
    public static LocalDate firstDayOfMonth() {
        LocalDate today = LocalDate.now();
        return LocalDate.of(today.getYear(), today.getMonth(), 1);
    }

    /**
     * 获取当前月份的最后一天
     *
     * @return 当前月份的最后一天
     */
    public static LocalDate lastDayOfMonth() {
        LocalDate today = LocalDate.now();
        return today.with(TemporalAdjusters.lastDayOfMonth());
    }
}
